﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace rozklad
{
    public partial class Form1 : Form
    {
        List<double[]> Stos_u = new List<double[]>();
        List<double[]> Stos_v = new List<double[]>();
        List<double> Stos_B = new List<double>();
        int ile_macierzy = 3;

        public Form1()
        {
            InitializeComponent();
        }

        private double IloczynSkalarnyL(double[] wektor1, double[] wektor2)
        {
            double iloczyn = 0;
            double[] wektor1_kopia = (double[])wektor1.Clone();
            double[] wektor2_kopia = (double[])wektor2.Clone();
            for (int i = 0; i < wektor1.Length; i++)
            {
                iloczyn += (wektor1_kopia[i] * wektor2_kopia[i]);
            }
            return iloczyn;
        }

        private double[] normalizacja(double[] wektor)
        {
            double zmienna = dlugosc(wektor);
            double[] wektor_kopia = (double[])wektor.Clone();
            double[] wynik = new double[wektor.Length];
            for (int i = 0; i < wektor.Length; i++) wynik[i] = (wektor_kopia[i] / zmienna);
            return wynik;
        }

        private double[] Mnozenie(double skalar, double[] wektor)
        {
            double[] wynik = new double[wektor.Length];
            double[] wektor_kopia = (double[])wektor.Clone();
            for (int i = 0; i < wektor.Length; i++)
            {
                wynik[i] = skalar * wektor_kopia[i];
            }
            return wynik;
        }

        private double[,] Mnozenie(double skalar, double[,] macierz)
        {
            double[,] wynik = new double[macierz.GetLength(0), macierz.GetLength(1)];
            double[,] macierz_kopia = (double[,])macierz.Clone();
            for (int i = 0; i < macierz.GetLength(0); i++)
            {
                for (int j = 0; j < macierz.GetLength(1); j++)
                {
                    wynik[i, j] = skalar * macierz_kopia[i, j];
                }
            }
            return wynik;
        }

        private double[] Mnozenie(double[,] macierz, double[] wektor)
        {
            //kolumna
            double[,] macierz_kopia = (double[,])macierz.Clone();
            double[] wektor_kopia = (double[])wektor.Clone();
            double[] wynik = new double[macierz.GetLength(0)];
            for (int i = 0; i < wynik.Length; i++)
            {
                wynik[i] = 0;
                for (int j = 0; j < macierz.GetLength(1); j++) wynik[i] = wynik[i] + macierz_kopia[i, j] * wektor_kopia[j];
            }
            return wynik;
        }

        private double[] Mnozenie(double[] wektor, double[,] macierz)
        {
            //wiersz
            double[] wektor_kopia = (double[])wektor.Clone();
            double[,] macierz_kopia = (double[,])macierz.Clone();
            double[] wynik = new double[macierz.GetLength(1)];
            for (int i = 0; i < wynik.Length; i++)
            {
                wynik[i] = 0;
                for (int j = 0; j < macierz.GetLength(0); j++) wynik[i] = wynik[i] + macierz_kopia[j, i] * wektor_kopia[j];
            }
            return wynik;
        }

        private double[,] Mnozenie(double[] wektor_pionowy, double[] wektor_poziomy)
        {
            double[] wektor_pionowy_kopia = (double[])wektor_pionowy.Clone();
            double[] wektor_poziomy_kopia = (double[])wektor_poziomy.Clone();
            double[,] wynik = new double[wektor_pionowy.Length, wektor_poziomy.Length];
            for (int i = 0; i < wektor_poziomy.Length; i++)
            {
                for (int j = 0; j < wektor_pionowy.Length; j++)
                {
                    wynik[j, i] = wektor_pionowy_kopia[j] * wektor_poziomy_kopia[i];
                }
            }
            return wynik;
        }

        private double[] ortogonalizacja(double[] wektor1, bool parametr)
        {
            double[] wynik = new double[wektor1.Length];
            double[] wektor1_kopia = (double[])wektor1.Clone();
            if ((Stos_u.Count == 0) && (parametr == true)) return wektor1_kopia;
            else if ((Stos_v.Count == 0) && (parametr == false)) return wektor1_kopia;
            else
            {
                if (parametr == true)
                {
                    for (int i = 0; i < Stos_u.Count; i++)
                    {
                        double[] Rzut;
                        double IloczunUV = IloczynSkalarnyL(wektor1_kopia, Stos_u[i]);
                        double IloczynUU = IloczynSkalarnyL(Stos_u[i], Stos_u[i]);
                        Rzut = Mnozenie((IloczunUV) / (IloczynUU), Stos_u[i]);
                        wynik = OdejmijWektory(wektor1_kopia, Rzut);
                    }
                    return wynik;
                }
                else //if (parametr == false)
                {
                    for (int i = 0; i < Stos_v.Count; i++)
                    {
                        double[] Rzut;
                        double IloczunUV = IloczynSkalarnyL(wektor1_kopia, Stos_v[i]);
                        double IloczynUU = IloczynSkalarnyL(Stos_v[i], Stos_v[i]);
                        Rzut = Mnozenie((IloczunUV) / (IloczynUU), Stos_v[i]);
                        wynik = OdejmijWektory(wektor1_kopia, Rzut);
                        // double[] Rzut = Mnozenie((IloczynSkalarnyL(wektor1, Stos_v[i])) / (IloczynSkalarnyL(Stos_v[i], Stos_v[i])), Stos_v[i]);
                        // wynik = OdejmijWektory(wektor1, Rzut);
                    }
                    return wynik;
                }
            }
        }

        private double dlugosc(double[] wektor)
        {
            double suma = 0;
            double[] wektor_kopia = (double[])wektor.Clone();
            for (int i = 0; i < wektor.Length; i++) suma += Math.Pow(wektor_kopia[i], 2);
            double zmienna = Math.Sqrt(suma);
            return zmienna;
        }

        private double[] OdejmijWektory(double[] wektor1, double[] wektor2)
        {
            double[] wektor1_kopia = (double[])wektor1.Clone();
            double[] wektor2_kopia = (double[])wektor2.Clone();
            double[] wynik = new double[wektor2.Length];
            for (int i = 0; i < wektor1.Length; i++) wynik[i] = wektor1_kopia[i] - wektor2_kopia[i];
            return wynik;
        }

        private double[,] OdejmijMacierze(double[,] macierz1, double[,] macierz2)
        {
            double[,] macierz1_kopia = (double[,])macierz1.Clone();
            double[,] macierz2_kopia = (double[,])macierz2.Clone();
            double[,] wynik = new double[macierz1.GetLength(0), macierz2.GetLength(1)];
            for (int y = 0; y < macierz1.GetLength(0); y++)
            {
                for (int x = 0; x < macierz1.GetLength(1); x++) wynik[y, x] = macierz1_kopia[y, x] - macierz2_kopia[y, x];
            }
            return wynik;
        }

        private double[,] DodajMacierze(double[,] macierz1, double[,] macierz2)
        {
            double[,] wynik = new double[macierz1.GetLength(0), macierz2.GetLength(1)];
            double[,] macierz1_kopia = (double[,])macierz1.Clone();
            double[,] macierz2_kopia = (double[,])macierz2.Clone();

            for (int y = 0; y < macierz1.GetLength(0); y++)
            {
                for (int x = 0; x < macierz1.GetLength(1); x++) wynik[y, x] = macierz1_kopia[y, x] + macierz2_kopia[y, x];
            }
            return wynik;
        }

        private void Magia(double[,] macierz_oryginal)
        {
            double[,] macierz = (double[,])macierz_oryginal.Clone();
 
            Random randomizer = new Random();
            double[] kolumna = new double[macierz.GetLength(1)]; //kolumna o l. elementow rownej szerokosci obrazka
            double[] wiersz = new double[macierz.GetLength(0)]; //wiersz o l. elementow rownej wysokosci obrazka
            double[] temp_kolumna = new double[macierz.GetLength(1)];
            double[] temp_wiersz = new double[macierz.GetLength(0)];
            double Epsilon = 0.01;

            int i = 0; int counter = 0;
            while (i < ile_macierzy) //szukanie i< wektorów
            {
                //losowanie kolumny wejsciowej
                for (int j = 0; j < kolumna.Length; j++) kolumna[j] = (((randomizer.Next(2000)) / 1000.0) - 1.0);
                kolumna = normalizacja(kolumna);
                kolumna = ortogonalizacja(kolumna, false);
                kolumna = normalizacja(kolumna);
                wiersz = Mnozenie(macierz, kolumna);
                wiersz = normalizacja(wiersz);
                wiersz = ortogonalizacja(wiersz, true);
                wiersz = normalizacja(wiersz);
                double[] roznica_w;
                double[] roznica_k;
                double rw;
                double rk;
                do
                {
                    temp_kolumna = kolumna;
                    temp_wiersz = wiersz;
                    wiersz = Mnozenie(macierz, kolumna);
                    wiersz = normalizacja(wiersz);
                    wiersz = ortogonalizacja(wiersz, true);
                    wiersz = normalizacja(wiersz);
                    kolumna = Mnozenie(wiersz, macierz);
                    kolumna = normalizacja(kolumna);
                    kolumna = ortogonalizacja(kolumna, false);
                    kolumna = normalizacja(kolumna);
                    roznica_w = OdejmijWektory(wiersz, temp_wiersz);
                    roznica_k = OdejmijWektory(kolumna, temp_kolumna);
                    rw = dlugosc(roznica_w);
                    rk = dlugosc(roznica_k);
                    counter++;
                } while ((rw > Epsilon) || (rk > Epsilon) || (counter == 200));
               
                double[] pom = Mnozenie(macierz, kolumna);
                double Beta = dlugosc(pom);

                Stos_B.Add(Beta);
                Stos_u.Add(wiersz);
                Stos_v.Add(kolumna);
                i++;
            }
        }

        public void button1_Click(object sender, EventArgs e)
        {
            Color kolor; Bitmap bitmapa = new Bitmap(Bitmap.FromFile(@"C:\klatki\klatki2\referencja.bmp"));

            //przepisanie obrazka do macierzy w odc szarosci
            double[,] greymatrix = new double[bitmapa.Height, bitmapa.Width];
            for (int y = 0; y < bitmapa.Height; y++)
            {
                for (int x = 0; x < bitmapa.Width; x++)
                {
                    kolor = bitmapa.GetPixel(x, y);
                    int greyScale = (int)((kolor.R * .3) + (kolor.G * .59) + (kolor.B * .11));
                    greymatrix[y, x] = greyScale;
                }
            }

            //Random randomizer = new Random();
            //double[] kolumna = new double[greymatrix.GetLength(1)]; //kolumna o l. elementow rownej szerokosci obrazka
            //double[] wiersz = new double[greymatrix.GetLength(0)]; //wiersz o l. elementow rownej wysokosci obrazka
            //double[] temp_kolumna = new double[greymatrix.GetLength(1)];
            //double[] temp_wiersz = new double[greymatrix.GetLength(0)];
            //double Epsilon = 0.01;

            ////znalezienie 2 największych Bet
            ////---1. szukanie największej bety przy pustym stosie
            ////------losowanie kolumny wejsciowej
            //    for (int j = 0; j < kolumna.Length; j++) kolumna[j] = (((randomizer.Next(2000)) / 1000.0) - 1.0);

            ////------normalizacja kolumny
            //    //------obliczenie dlugosci kolumny
            //    double suma = 0;
            //    double[] wektor_kopia = (double[])kolumna.Clone();
            //    for (int i = 0; i < wektor.Length; i++) suma += Math.Pow(wektor_kopia[i], 2);
            //    double zmienna = Math.Sqrt(suma);
            //    double[] wynik = new double[wektor_kopia.Length];
            //    for (int i = 0; i < wektor.Length; i++) wynik[i] = (wektor_kopia[i] / zmienna);

            Magia(greymatrix); //wywolanie rozkladu dla uzyskanej macierzy

            for (int i = 0; i < Stos_B.Count; i++) richTextBox1.AppendText(Stos_B[i].ToString() + "\n");
            Bitmap przyblizenie = new Bitmap(720, 576);
            double[,] obrazek2 = new double[576, 720];

            for (int z = 0; z < ile_macierzy; z++)
            {
                double[,] obrazek = new double[576, 720];
                obrazek = Mnozenie(Stos_u[z], Stos_v[z]);
                obrazek = Mnozenie(Stos_B[z], obrazek);
                obrazek2 = DodajMacierze(obrazek2, obrazek);
            }

            for (int i = 0; i < 576; i++)
            {
                for (int j = 0; j < 720; j++)
                {
                    double kolor_macierz = obrazek2[i, j];
                    if (kolor_macierz > 255) { kolor_macierz = 255.0; }
                    else if (kolor_macierz < 0) { kolor_macierz = 0.0; }
                    przyblizenie.SetPixel(j, i, Color.FromArgb((int)kolor_macierz, (int)kolor_macierz, (int)kolor_macierz));
                }
            }
            pictureBox1.Width = 720;
            pictureBox1.Height = 576;
            pictureBox1.BackgroundImage = przyblizenie;
        }

        private void button2_Click(object sender, EventArgs e)
        {
        }

        private void button3_Click(object sender, EventArgs e)
        {
        }
    }
}